// src/tests.rs
mod mimalloc;

mod tests {
    use std::thread;
    use libc_print::libc_println;
    use mimalloc::*;

    use super::*;

    fn test_heap(p_out: *mut u8) {
        let heap = mi_heap_new();
        let _ = mi_heap_malloc(heap, 32);
        let _ = mi_heap_malloc(heap, 48);
        _mi_free(p_out);
        mi_heap_destroy(heap);
    }

    fn test_large(my_allocator: &MyAllocator) {
        const N: usize = 100;
        for _ in 0..N {
            let sz:usize = 1 << 21;
            let a = my_allocator.mi_malloc(sz) as *mut char;
            for i in 0..sz {
                unsafe {
                    *a.add(i) = 'x';
                }
            }
            my_allocator.mi_free(a as *mut u8);
        }
    }

    #[test]
    fn test_mi_malloc() {
        let my_allocator = MyAllocator;
        let mut p1 = my_allocator.mi_malloc(16);
        let mut p2 = my_allocator.mi_malloc(1000000);
        my_allocator.mi_free(p1);
        my_allocator.mi_free(p2);
        p1 = my_allocator.mi_malloc(16);
        p2 = my_allocator.mi_malloc(16);
        my_allocator.mi_free(p1);
        my_allocator.mi_free(p2);

        test_large(&my_allocator);

        test_heap(my_allocator.mi_malloc(32));
        my_allocator.mi_collect(true);
    }

    #[test]
    fn test_mi_malloc_mt() {
        libc_println!("empty heap {:p}", &_MI_HEAP_EMPTY);
        unsafe {
            libc_println!("Main process({:x}): I am from heap 0x{:x}", (*get_heap_default()).thread_id as usize, get_heap_default() as usize);
            let handle = thread::spawn(|| {
                let a = Box::new(5);
                libc_println!("Thread({}): I am from heap 0x{:x}",(*get_heap_default()).thread_id as usize, get_heap_default() as usize);
                drop(a);
            });
            handle.join().unwrap();
        }
    }
}